
//=============================================================================
//
//Module Name:					axi_w_channel.sv
//Department:					Xidian University
//Function Description:	        AXI总线从设备写通道
//
//------------------------------------------------------------------------------
//
//Version 	Design		Coding		Simulata	  Review		Rel data
//V1.0		Verdvana	Verdvana	Verdvana		  			2020-3-19
//
//------------------------------------------------------------------------------
//
//Version	Modified History
//V1.0		将sram控制器连接到AXI总线;
//          生成sram控制信号：sram地址，rd / wr操作和片选信号等。
//
//=============================================================================

`timescale 1ns/1ns

module axi_w_channel#(
    parameter   DATA_WIDTH  = 64,             	//数据位宽
                ADDR_WIDTH  = 32,               //地址位宽              
                ID_WIDTH    = 1,               	//ID位宽
                USER_WIDTH  = 1,             	//USER位宽
                STRB_WIDTH  = (DATA_WIDTH/8)	//STRB位宽
)(
    /********* 时钟&复位 *********/
	input                       ACLK,
	input      	                ARESETn,
	/******** AXI总线信号 ********/
    //写地址通道
	input      [ID_WIDTH-1:0]   AWID,
	input	   [ADDR_WIDTH-1:0] AWADDR,
	input	   [7:0]            AWLEN,
	input	   [2:0]            AWSIZE,
	input	   [1:0]	        AWBURST,
//	input	  	                AWLOCK,
//	input	   [3:0]	        AWCACHE,
//	input	   [2:0]	        AWPROT,
//	input	   [3:0]	        AWQOS,
//	input	   [3:0]            AWREGION,
//	input	   [USER_WIDTH-1:0]	AWUSER,
	input	 	                AWVALID,
	output reg	                AWREADY,
	//写数据通道                
//	input	   [ID_WIDTH-1:0]   WID,
	input	   [DATA_WIDTH-1:0] WDATA,
	input	   [STRB_WIDTH-1:0] WSTRB,
	input		                WLAST,
//	input	   [USER_WIDTH-1:0]	WUSER,
	input	  	                WVALID,
	output reg	                WREADY,
	//写响应通道                
	output reg [ID_WIDTH-1:0]   BID,
	output     [1:0]            BRESP,
//	output reg [USER_WIDTH-1:0]	BUSER,
	output reg	                BVALID,
	input	  	                BREADY,
	/********** 输出信号 **********/
	output reg					wen,
	output reg [3:0]			awsize,
	output reg [31:0]			awaddr,
	output reg [63:0]			wdata
);  

    //=========================================================
    //常量定义
    parameter   TCO     =   1;  	//寄存器延时

	//=========================================================
    //中间信号
	reg	[15:0]	awaddr_start;	//起始地址
	reg	[15:0]	awaddr_stop;	//终止地址（不加起始地址）
	reg	[15:0]	awaddr_cnt;		//地址计数器
	reg	[8:0]	awaddr_step;	//地址步进长度
	reg			awaddr_cnt_flag;//地址累加标志
	reg   [7:0]	awlen;			//awlen
	reg [ID_WIDTH-1:0]bid;


    //======================================================================
    //握手

	//----------------------------------------------------------------------
    //AWREADY回应
	always@(posedge ACLK or negedge ARESETn)begin
		if(!ARESETn)
			AWREADY	<= '0;
		else if(AWVALID&&!AWREADY)
			AWREADY	<= '1;
		else
			AWREADY	<= '0;
	end

	//----------------------------------------------------------------------
    //WREADY回应
	always@(posedge ACLK or negedge ARESETn)begin
		if(!ARESETn)
			WREADY	<= '0;
		else if(AWREADY)
			WREADY	<= '1;
		else if(WVALID&&WLAST)
			WREADY	<= '0;	
		else
			WREADY	<= WREADY;
	end

	//----------------------------------------------------------------------
    //BVALID回应
	always@(posedge ACLK or negedge ARESETn)begin
		if(!ARESETn)
			BVALID	<= '0;
		else if(~BVALID&&WLAST)
			BVALID	<= '1;
		else
			BVALID	<= '0;
	end
	//BID
	always@(posedge ACLK or negedge ARESETn)begin
		if(!ARESETn)
			BID	<= '0;
		else if(~BVALID&&WLAST)
			BID	<= bid;
		else
			BID	<= BID;
	end
    //======================================================================
    //参数寄存	
	always@(posedge ACLK or negedge ARESETn)begin
		if(!ARESETn)begin
			awaddr_start	<= '0;
			awlen			<= '0;
			awsize			<= '0;
			bid				<= '0;
		end
		else if(AWVALID)begin
			awaddr_start	<= AWADDR[15:0];	//起始地址寄存
			awlen			<= AWLEN;			//突发长度寄存
			awsize			<= AWSIZE;			//数据宽度寄存
			bid				<= AWID;

		end
		else begin
			awaddr_start	<= awaddr_start;
			awlen			<= awlen;
			awsize			<= awsize;
			bid				<= bid;
		end
	end


	//======================================================================
    //写地址累加
	//assign	awaddr_step	= 2**awsize;			//计算步进
	always@(*) begin
		case(awsize)
			3'h0:	awaddr_step = 16'h1;
			3'h1:	awaddr_step = 16'h2;
			3'h2:	awaddr_step = 16'h4;
			default:awaddr_step = 16'h1;
		endcase
	end

	//assign	awaddr_stop = awlen*awaddr_step;	//计算步进次数
	always@(*) begin
		case(awsize)
			3'h0:	awaddr_stop = {8'h0,awlen};
			3'h1:	awaddr_stop = {7'h0,awlen,1'b0};
			3'h2:	awaddr_stop = {6'h0,awlen,2'b0};
			default:awaddr_stop = {8'h0,awlen};
		endcase
	end


	always@(posedge ACLK or negedge ARESETn)begin
		if(!ARESETn)
			awaddr_cnt_flag	<= '0;
		else if(AWVALID)
			awaddr_cnt_flag <= '1;
		else if(awlen=='0)
			awaddr_cnt_flag <= '0;
		else if(awaddr_cnt==awaddr_stop)
			awaddr_cnt_flag <= '0;
	end

	always@(posedge ACLK or negedge ARESETn)begin
		if(!ARESETn)
			awaddr_cnt	<= '0;
		else if(awaddr_cnt_flag)
			awaddr_cnt	<= awaddr_cnt + awaddr_step;
		else
			awaddr_cnt	<= '0;
	end


	//======================================================================
	//输出信号

	//----------------------------------------------------------------------
    //使能
	always@(posedge ACLK or negedge ARESETn)begin
		if(!ARESETn)
			wen	<= '0;
		else if(WLAST)
			wen	<= '0;
		else if(AWREADY)
			wen	<= '1;
		else
			wen	<= wen;
	end

	//----------------------------------------------------------------------
    //写数据
	always@(*) begin
		case(awsize)
			3'b000:	wdata = {56'b0,WDATA[7:0]};	//8bit
			3'b001:	wdata = {48'b0,WDATA[15:0]};//16bit
			3'b010:	wdata = {31'b0,WDATA[31:0]};		//32bit
			3'b011:	wdata = WDATA[63:0];		
			default:wdata = WDATA[63:0];
		endcase
	end


	//----------------------------------------------------------------------
    //写地址
	always@(posedge ACLK or negedge ARESETn)begin
		if(!ARESETn)
			awaddr	<= '0;
		else
			awaddr 	<=  awaddr_start + awaddr_cnt;
	end

	//======================================================================
	//其他信号

	//----------------------------------------------------------------------
    //回应
	
	assign	BRESP = '0;

	


endmodule                                     